package main

import (
	"flag"
	"fmt"
	"go-tun2socks/common/log"
	mytun "go-tun2socks/test"
	"net"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

type CmdArgs struct {
	Version         *bool
	TunName         *string
	TunAddr         *string
	TunGw           *string
	TunMask         *string
	TunDns          *string
	TunPersist      *bool
	BlockOutsideDns *bool
	ProxyType       *string
	ProxyServer     *string
	ProxyHost       *string
	ProxyPort       *uint16
	UdpTimeout      *time.Duration
	LogLevel        *string
	DnsFallback     *bool
	WriteServer		*string
	ReadServer		*string
}

var postFlagsInitFn = make([]func(), 0)

func addPostFlagsInitFn(fn func()) {
	postFlagsInitFn = append(postFlagsInitFn, fn)
}


type cmdFlag uint
var args = new(CmdArgs)

func main(){
	args.Version = flag.Bool("version", false, "Print version")
	args.TunName = flag.String("tunName", "tun1", "TUN interface name")
	args.TunAddr = flag.String("tunAddr", "10.255.0.2", "TUN interface address")
	args.TunGw = flag.String("tunGw", "10.255.0.1", "TUN interface gateway")
	args.TunMask = flag.String("tunMask", "255.255.255.0", "TUN interface netmask, it should be a prefixlen (a number) for IPv6 address")
	args.TunDns = flag.String("tunDns", "8.8.8.8,8.8.4.4", "DNS resolvers for TUN interface (only need on Windows)")
	args.TunPersist = flag.Bool("tunPersist", false, "Persist TUN interface after the program exits or the last open file descriptor is closed (Linux only)")
	args.BlockOutsideDns = flag.Bool("blockOutsideDns", false, "Prevent DNS leaks by blocking plaintext DNS queries going out through non-TUN interface (may require admin privileges) (Windows only) ")
	args.ProxyType = flag.String("proxyType", "socks", "Proxy handler type")
	args.LogLevel = flag.String("loglevel", "info", "Logging level. (debug, info, warn, error, none)")
	args.ProxyServer = flag.String("proxyServer", "1.2.3.4:1087", "Proxy server address")
	args.WriteServer = flag.String("writeServer","127.0.0.1:1081","Write Server address")
	args.ReadServer = flag.String("readServer","127.0.0.1:1080","Write Server address")

	flag.Parse()

	// Initialization ops after parsing flags.
	for _, fn := range postFlagsInitFn {
		if fn != nil {
			fn()
		}
	}
	fmt.Println(*args.WriteServer)
	tunReaderChannel, err := net.Dial("tcp", *args.ReadServer)
	tunWriterChannel, err2 := net.Dial("tcp", *args.WriteServer)
	if err != nil || err2 != nil{
		fmt.Println("无法和java VPN客户端进行连接")
		return
	}

	dns := strings.Split(*args.TunDns,",")
	tun, err := mytun.OpenTunDevice(
		*args.TunName,
		*args.TunAddr,
		*args.TunGw,
		"255.255.255.0",
		dns,
		true)
	if err != nil {
		fmt.Println("error")
	}
	defer tun.Close()

	// thread 1: 从tun中读取数据，发送到java进程
	go func() {
		data := make([]byte, 1500)
		for {
			nr, err := tun.Read(data)
			if err != nil || nr < 0{
				log.Fatalf("read from tun err: %v", err)
				syscall.Exit(21)
			}
			src := net.IP(data[12:16])
			dst := net.IP(data[16:20])
			ipHeaderLen := (data[0] & 0x0f) * 4
			fmt.Println("nr = ", nr,
				" src:", src, " dst:", dst,
				"protocol:", data[9], "iphLen:", ipHeaderLen)
			//fmt.Println(data[0:ipHeaderLen + 8])
			mdnsIP := []byte{224,0,0,251}
			if dst.Equal(mdnsIP){ // mdns 直接跳过
				//fmt.Println("mdns")
			} else {
				_, err := tunReaderChannel.Write(data[:nr])
				if err != nil{
					log.Fatalf("write to TCP channel err: %v", err)
				}
			}

		}
	}()
	// thread 2: 从java中获取数据，写入tun中
	go func() {
		data := make([]byte, 1500)
		for {
			nw, err := tunWriterChannel.Read(data)
			if err != nil || nw < 0{
				log.Fatalf("read from TCP channel err: %v",err)
				syscall.Exit(22)
			}
			if nw == 0{
				continue
			} else {
				_, err := tun.Write(data[:nw])
				if err != nil{
					log.Fatalf("write to tun error: %v", err)
				}
			}
		}
	}()


	osSignals := make(chan os.Signal, 1)
	signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	<-osSignals
}